/*
Atom:  brief Definition of Atom class and atom´s Aspects.
    Copyright (C) 2010  Jorge E. A. Atala
                        FuDePAN
    This file is part of the Biopp Proyect.

    Biopp is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Biopp is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Biopp.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef ATOM_H
#define ATOM_H

namespace biopp
{

class NIL_Atom_Aspect { } ;

template < class A, class DistanceUnit = float >
class Coord3d_Aspect : public A
{
public:
    typedef DistanceUnit Coord;
    Coord x, y, z;

    inline Coord3d_Aspect()
        :   x(0),
            y(0),
            z(0)
    {
    }

    inline Coord3d_Aspect(Coord x , Coord y, Coord z)
        :   x(x),
            y(y),
            z(z)
    {
    }

    inline Coord3d_Aspect(const Coord3d_Aspect& other)
        :   x(other.x),
            y(other.y),
            z(other.z)
    {
    }

    inline Coord3d_Aspect& operator += (const Coord3d_Aspect& other)
    {
        x += other.x;
        y += other.y;
        z += other.z;
        return (*this);
    }

    inline Coord3d_Aspect& operator /= (Coord f)
    {
        x /= f;
        y /= f;
        z /= f;
        return (*this);
    }

    inline Coord xDistance(const Coord3d_Aspect& other) const
    {
        return x - other.x;
    }

    inline Coord yDistance(const Coord3d_Aspect& other) const
    {
        return y - other.y;
    }

    inline Coord zDistance(const Coord3d_Aspect& other) const
    {
        return z - other.z;
    }

    inline Coord squareDistance(const Coord3d_Aspect& other) const
    {
        return mili::square(x - other.x) +
               mili::square(y - other.y) +
               mili::square(z - other.z);
    }

};



template <class A>
class AtomType_Aspect : public A
{
public:
    enum AtomType {N, CA, C};
    AtomType vdw;

    inline AtomType_Aspect():
        A(),
        vdw(N)
    {
    }


    inline AtomType_Aspect(AtomType type, const A& other):
        A(other),
        vdw(type)
    {
    }

    inline AtomType_Aspect(const AtomType_Aspect& other):
        A(other),
        vdw(other.vdw)
    {
    }
};

typedef Coord3d_Aspect< NIL_Atom_Aspect, float > Coord3d;
typedef AtomType_Aspect< Coord3d > AtomWithTypeAnd3DCoords;

}
#endif
